﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace ExchangeHog.MessageParser
{
	public class DummyHeaderContentsToken : BaseToken
	{
		internal enum TokenType { NONE, SPACE, CRLF, HEADERCONTENTS, EOF };
		internal TokenType TType { get; private set; }
		public String Repr { get; internal set; }
		internal int TokenTypeAsInt() { return (int)TType; }

		internal DummyHeaderContentsToken(TokenType tt = TokenType.NONE, string repr = null) { TType = tt; Repr = repr; }

		internal void MarkAsCRLF() { TType = TokenType.CRLF; }
		internal void MarkAsSPACE() { TType = TokenType.SPACE; }

		internal bool IsSPACE() { return TType == TokenType.SPACE; }
	}

	public class DummyHeaderContentsLexer : BaseLexer<DummyHeaderContentsToken>
	{
		void ParseHeaderContents()
		{
			StringBuilder sb = new StringBuilder();
			bool isEndOfHeaderContentsReached = false;

			if (!IsEndOfStream())
				do
				{
					Char ch = PeekChar();
					switch (ch)
					{
						case '\r':
							ch = PeekChar2();
							if (ch == '\n')
							{
								//
								//	Check for continuation line
								//
								ch = PeekChar3();
								if (ch == ' ' || ch == '\t')
								{
									SkipChar(); // \n
									SkipChar(); // ' ' or '\t'
									sb.Append(ch);
								}
								else
									isEndOfHeaderContentsReached = true;
							}
							break;
						default:
							sb.Append(ch);
							break;
					}
				} while (!IsEndOfStream() && !isEndOfHeaderContentsReached);
			Tokens.Enqueue(new DummyHeaderContentsToken(DummyHeaderContentsToken.TokenType.HEADERCONTENTS, sb.ToString()));
		} // end of ParseHeaderContents

		public DummyHeaderContentsToken NextToken()
		{
			if (Tokens.Count == 0)
				do
					if (!IsEndOfStream())
					{
						Char ch = PeekChar();
						switch (ch)
						{
							case '\r': ParseCRLF(); break;
							default:
								if (32 < (short)ch && (short)ch < 127)
									ParseHeaderContents();
								else
									throw new ApplicationException("Unexpected character '" + ch + "'");
								break;
						}
					}
					else
						Tokens.Enqueue(new DummyHeaderContentsToken(DummyHeaderContentsToken.TokenType.EOF));
				while (Tokens.Count == 0 && !IsEndOfStream());
			return Tokens.Dequeue();
		} // end of NextToken

		public DummyHeaderContentsToken ParseThis(DummyHeaderContentsToken.TokenType ttExpected)
		{
			return base.ParseThis(ttExpected);
		}
	}
}
